package com.sf.fy.uav.applet.coupon;

import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sf.fy.uav.applet.config.DelayQueue;
import com.sf.fy.uav.common.enums.*;
import com.sf.fy.uav.common.request.operate.CouponIntroductionReq;
import com.sf.fy.uav.common.request.operate.CouponRequest;
import com.sf.fy.uav.common.request.operate.QueryCouponRequest;
import com.sf.fy.uav.common.request.operate.UserInfoReq;
import com.sf.fy.uav.common.response.operational.*;
import com.sf.fy.uav.common.utils.BeanUtil;
import com.sf.fy.uav.common.utils.PhoneEncoderUtil;
import com.sf.fy.uav.common.utils.RedisPrefixKey;
import com.sf.fy.uav.common.utils.Rs;
import com.sf.fy.uav.controller.CouponActivityDetailController;
import com.sf.fy.uav.controller.CouponIntroductionUserRest;
import com.sf.fy.uav.controller.UserCouponRest;
import com.sf.fy.uav.entity.Coupon;
import com.sf.fy.uav.entity.CouponActivityDetail;
import com.sf.fy.uav.entity.CouponIntroductionUser;
import com.sf.fy.uav.entity.UserCoupon;
import com.sf.fy.uav.mapper.UserCouponMapper;
import com.sf.fy.uav.order.controller.OrderInfoRest;
import com.sf.fy.uav.order.entity.OrderInfo;
import com.sf.fy.uav.rest.CouponRest;
import com.sf.fy.uav.user.rest.UserRest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ta136817
 */
@RestController
@RequestMapping("/home/coupon")
@Tag(name = "优惠券管理", description = "优惠券管理")
public class CouponController {
    @Autowired
    private CouponRest couponRest;

    @Autowired
    private UserCouponRest userCouponRest;

    @Autowired
    private CouponActivityDetailController couponActivityDetailController;

    @Autowired
    UserRest userRest;

    @Autowired
    private OrderInfoRest orderInfoRest;
    @Autowired
    private CouponIntroductionUserRest couponIntroductionUserRest;
    @Autowired
    private PhoneEncoderUtil phoneEncoderUtil;

    @Autowired
    private UserCouponMapper userCouponMapper;


    @Autowired
    private DelayQueue delayQueue;

    private final static Integer CONST_NUM = 0;
    private final static Byte NEW_USER = 1;

    @GetMapping("get-coupon")
    @Operation(tags = "获取优惠券列表", description = "获取优惠券列表")
    @CrossOrigin
    @Parameter(name = "page", description = "页码")
    @Parameter(name = "size", description = "单页条数")
    @Parameter(name = "couponName", description = "优惠券名称")
    @Parameter(name = "status", description = "优惠券状态")
    public Rs<List<CouponResponse>> getCoupons(@RequestParam Integer page, @RequestParam Integer size, @RequestParam(required = false) String couponName, @RequestParam(required = false) Byte status) {
        QueryCouponRequest queryCouponRequest = new QueryCouponRequest();
        queryCouponRequest.setCurrent(page);
        queryCouponRequest.setSize(size);
        queryCouponRequest.setCouponName(couponName);
        queryCouponRequest.setStatus(status);
        return Rs.success(couponRest.getCoupons(queryCouponRequest));
    }

    @GetMapping("get-total")
    @CrossOrigin
    @Operation(tags = "获取优惠券列表条数", description = "获取优惠券列表")
    @Parameter(name = "couponName", description = "优惠券名称")
    @Parameter(name = "status", description = "优惠券状态")
    public Rs<Long> getTotal(@RequestParam(required = false) String couponName, @RequestParam(required = false) Byte status) {
        return Rs.success(couponRest.getTotal(couponName, status));
    }

    @PostMapping("create")
    @Operation(tags = "创建优惠券", description = "创建优惠券")
    @ApiResponses({@ApiResponse(responseCode = "200", description = "成功,非200失败")})
    public Rs<Void> createCoupon(@RequestBody CouponRequest couponRequest) {
        Coupon coupon = couponRest.createCoupon(couponRequest);
        if (ObjectUtils.isEmpty(coupon.getEffectiveDays())) {
            Date startTime = coupon.getEffectiveTime();
            Date endTime = coupon.getFailureTime();
            Date date = coupon.getCreateTime();
            if (startTime.getTime() > date.getTime()) {
                //还没开始
//            //设置到期自动上架
                delayQueue.pushQueue(ServicePrefixEnum.EXPRESS_SYSTEM + RedisPrefixKey.COUPON_UP_COUNT_DOWN + coupon.getId(), startTime.getTime() - date.getTime());
            } else {
                if (date.getTime() < endTime.getTime()) {
//                //设置到期自动下架
                    delayQueue.pushQueue(ServicePrefixEnum.EXPRESS_SYSTEM + RedisPrefixKey.COUPON_DOWN_COUNT_DOWN + coupon.getId(), endTime.getTime() - date.getTime());
                }
            }
        }

        return Rs.success();
    }

    @PostMapping("edit")
    @Operation(tags = "编辑优惠券", description = "编辑优惠券")
    @Schema(title = "couponRequest", name = "couponRequest", description = "编辑优惠券请求", type = "结构体")
    @ApiResponses({@ApiResponse(responseCode = "200", description = "成功,非200失败")})
    public Rs<Void> editCoupon(@RequestBody CouponRequest couponRequest) {
        Coupon coupon = couponRest.editCoupon(couponRequest);
        if (ObjectUtils.isEmpty(coupon.getEffectiveDays())) {
            Date startTime = coupon.getEffectiveTime();
            Date endTime = coupon.getFailureTime();
            Date date = coupon.getUpdateTime();
            if (startTime.getTime() > date.getTime()) {
                //还没开始
//            //设置到期自动上架
                delayQueue.pushQueue(ServicePrefixEnum.EXPRESS_SYSTEM + RedisPrefixKey.COUPON_UP_COUNT_DOWN + coupon.getId(), startTime.getTime() - date.getTime());
            } else {
                if (date.getTime() < endTime.getTime()) {
//                //设置到期自动下架
                    delayQueue.pushQueue(ServicePrefixEnum.EXPRESS_SYSTEM + RedisPrefixKey.COUPON_DOWN_COUNT_DOWN + coupon.getId(), endTime.getTime() - date.getTime());
                }
            }
        }
        return Rs.success();
    }

    @PostMapping("delete")
    @Operation(tags = "删除优惠券", description = "删除优惠券")
    @Schema(title = "couponRequest", name = "couponRequest", description = "删除优惠券请求", type = "结构体")
    @ApiResponses({@ApiResponse(responseCode = "200", description = "成功,非200失败")})
    public Rs<Void> deleteCoupon(@RequestBody CouponRequest couponRequest) {
        couponRest.deleteCoupon(couponRequest);
        return Rs.success();
    }

    @PostMapping("introduction")
    @Operation(tags = "定向发放", description = "定向发放")
    public Rs<CouponIntroductionResult> introduction(@RequestBody CouponIntroductionReq couponIntroductionReq) {
        if (StringUtils.isBlank(couponIntroductionReq.getPhoneNumberList())) {
            throw new RuntimeException("定向发放用户不能为空!");
        }
        String[] phoneArray = StringUtils.deleteWhitespace(couponIntroductionReq.getPhoneNumberList()).split(",");
        if (ObjectUtils.isEmpty(phoneArray)) {
            throw new RuntimeException("手机号为空!");
        }
        Set<String> phoneSet = new HashSet<>(Arrays.asList(phoneArray));
        UserInfoReq userInfoReq = new UserInfoReq();
        userInfoReq.setPhoneArray(phoneArray);
        Map<String, String> userInfo = userRest.getUserInfoByUserIdOrPhone(userInfoReq);
        //存储全部手机号都在数据库中不存在的数据
        if (CollectionUtils.isEmpty(userInfo)) {
            CouponIntroductionResult couponIntroductionResult = new CouponIntroductionResult();
            couponIntroductionResult.setIntroductionUserNum(CONST_NUM);
            couponIntroductionResult.setUnregisteredPhone(phoneSet);
            List<CouponIntroductionUser> couponIntroductionUsers = new ArrayList<>();
            for (String phone : phoneSet) {
                CouponIntroductionUser couponIntroductionUser = new CouponIntroductionUser();
                couponIntroductionUser.setCouponId(couponIntroductionReq.getCouponId());
                couponIntroductionUser.setPhone(phoneEncoderUtil.encryptString(phone));
                couponIntroductionUser.setCreateTime(new Date());
                couponIntroductionUser.setUpdateTime(new Date());
                couponIntroductionUsers.add(couponIntroductionUser);
            }
            couponIntroductionUserRest.insertCouponIntroductionUsers(couponIntroductionUsers);
            return Rs.success(couponIntroductionResult);
        }
        Set<String> userIds = new HashSet<>();
        userInfo.forEach((userid, phone) -> {
            userIds.add(userid);
            //从所有前端传过来的手机号里移除掉从数据库里已经查到的手机号,即剩下的就是未注册的手机号
            phoneSet.remove(phoneEncoderUtil.decryptString(phone));
        });
        List<OrderInfo> orderInfoListByUserIds = orderInfoRest.getOrderInfoListByUserIds(userIds);
        //如果是新用户但是在小程序下过单,那么也要加入不能发放的名单里
        if (NEW_USER.equals(couponIntroductionReq.getDesignatedUserType()) && orderInfoListByUserIds.size() > CONST_NUM) {
            for (OrderInfo orderInfo : orderInfoListByUserIds) {
                phoneSet.add(phoneEncoderUtil.decryptString(userInfo.get(orderInfo.getUserId())));
                userIds.remove(orderInfo.getUserId());
            }
        }
        couponIntroductionReq.setPhoneSet(phoneSet);
        couponIntroductionReq.setPhoneArray(phoneArray);
        couponIntroductionReq.setUserIds(userIds);
        return userCouponRest.introduction(couponIntroductionReq);
    }

    @GetMapping("get-orUsePerson")
    @Operation(tags = "获取领/用券用户", description = "获取领/用券用户")
    @CrossOrigin
    @Parameter(name = "id", description = "优惠券id")
    public Rs<List<CouponGetOrUsePersonRes>> getOrUsePerson(@RequestParam Integer page, @RequestParam Integer size, @RequestParam(required = false) String id, @RequestParam(required = false) Integer couponStatus, @RequestParam(required = false) String phoneNumber) {
        //将明文手机号码进行加密，用于查询分页
        String decryptPhone = null;
        if (StrUtil.isNotBlank(phoneNumber)) {
            decryptPhone = phoneEncoderUtil.encryptString(phoneNumber);
        }
        Integer status = null;
        if (ObjectUtil.isNotNull(couponStatus) && couponStatus != -1) {
            status = couponStatus;
        }
        IPage<UserCoupon> iPage = userCouponMapper.findPage(new Page<UserCoupon>(page, size), id, status, decryptPhone);

//        Page<UserCoupon> userCouponPage = userCouponMapper.selectPage(new Page<>(page, size), new QueryWrapper<UserCoupon>().eq("coupon_id", id).eq(ObjectUtil.isNotNull(couponStatus) && couponStatus != -1, "status", couponStatus).orderByDesc("create_time").orderByDesc("status"));
//        Long cnt = userCouponMapper.selectCount(new QueryWrapper<UserCoupon>().eq("coupon_id", id));
        List<CouponGetOrUsePersonRes> couponGetOrUsePersonList = BeanUtil.copyProperties(iPage.getRecords(), CouponGetOrUsePersonRes.class);
//        Set<String> userSet = userCouponPage.getRecords().stream().map(UserCoupon::getUserId).collect(Collectors.toSet());
        Set<String> userCouponIdSet = iPage.getRecords().stream().map(UserCoupon::getId).collect(Collectors.toSet());
        List<OrderInfo> orderInfoList = orderInfoRest.getOrderInfoListByInUserCouponIds(userCouponIdSet);
        Map<String, String> userCouponIdAndOrderNoMap = orderInfoList.stream().collect(Collectors.toMap(OrderInfo::getUserCouponId, OrderInfo::getTcWaybillNo));
//        UserInfoReq userInfoReq = new UserInfoReq();
//        userInfoReq.setUserIds(userSet);
//        Map<String, String> userInfoMap = userRest.getUserInfoByUserIdOrPhone(userInfoReq);
//        if (StrUtil.isNotBlank(phoneNumber)) {
//            couponGetOrUsePersonList = couponGetOrUsePersonList.stream().filter(item -> phoneEncoderUtil.decryptString(userInfoMap.get(item.getUserId())).equals(phoneNumber)).toList();
//        }
        for (CouponGetOrUsePersonRes couponGetOrUsePersonRes : couponGetOrUsePersonList) {
            couponGetOrUsePersonRes.setPhoneNumber(DesensitizedUtil.mobilePhone(phoneEncoderUtil.decryptString(couponGetOrUsePersonRes.getPhoneNumber())));
            couponGetOrUsePersonRes.setTcWayBillNo(userCouponIdAndOrderNoMap.get(couponGetOrUsePersonRes.getId()));
            couponGetOrUsePersonRes.setSourceName(UserCouponSourceEnum.getDesc(couponGetOrUsePersonRes.getSource()));
            couponGetOrUsePersonRes.setStatusName(CouponGetOrUseStatusEnum.getDesc(couponGetOrUsePersonRes.getStatus()));
            couponGetOrUsePersonRes.setTotal(iPage.getTotal());
        }
        return Rs.success(couponGetOrUsePersonList);
    }

    @GetMapping("get-directedReleaseRecord")
    @Operation(tags = "获取定向发放记录", description = "获取定向发放记录")
    @CrossOrigin
    @Parameter(name = "id", description = "优惠券id")
    public Rs<List<CouponDirectedReleaseRes>> getDirectedReleaseRecord(@RequestParam Integer page, @RequestParam Integer size, @RequestParam(required = false) String id) {
        List<CouponDirectedReleaseRes> couponDirectedReleaseResList = new ArrayList<>();
        QueryWrapper<UserCoupon> queryWrapperGetUser = new QueryWrapper<>();
        queryWrapperGetUser.select("create_time as 'createTime',user_id as 'userId'").eq("coupon_id", id).groupBy("create_time,user_id");
        List<UserCoupon> userCoupons = userCouponMapper.selectList(queryWrapperGetUser);
        Set<String> userSet = userCoupons.stream().map(UserCoupon::getUserId).collect(Collectors.toSet());
        UserInfoReq userInfoReq = new UserInfoReq();
        userInfoReq.setUserIds(userSet);
        //userId和手机号对应的map
        Map<String, String> userInfoMap = userRest.getUserInfoByUserIdOrPhone(userInfoReq);
        List<CouponIntroductionUser> couponIntroductionUsers = couponIntroductionUserRest.getCouponIntroductionUsers(id);
        IdentityHashMap<Date, String> failRecMap = new IdentityHashMap<>();
        for (CouponIntroductionUser couponIntroductionUser : couponIntroductionUsers) {
            failRecMap.put(couponIntroductionUser.getCreateTime(), couponIntroductionUser.getPhone());
        }
        //分页分组并排序
        QueryWrapper<UserCoupon> queryWrapperGetReleaseRecord = new QueryWrapper<>();
        QueryWrapper<UserCoupon> userCouponQueryWrapper = queryWrapperGetReleaseRecord.select("create_time as 'createTime',count(*) as 'alreadyRecNum'").eq("coupon_id", id).eq("source", UserCouponSourceEnum.PASSIVE_ACQUISITION.getValue()).groupBy("create_time").orderByDesc("create_time");
        Page<Map<String, Object>> mapPage = userCouponMapper.selectMapsPage(new Page<>(page, size), userCouponQueryWrapper);
        List<Map<String, Object>> userCouponList = userCouponMapper.selectMaps(userCouponQueryWrapper);
        for (Map<String, Object> userCouponGroupMap : mapPage.getRecords()) {
            CouponDirectedReleaseRes couponDirectedReleaseRes = new CouponDirectedReleaseRes();
            LocalDateTime dateTime = (LocalDateTime) userCouponGroupMap.get("createTime");
            ZonedDateTime zonedDateTime = dateTime.atZone(ZoneId.systemDefault());
            Instant instant2 = zonedDateTime.toInstant();
            Date date2 = Date.from(instant2);
            couponDirectedReleaseRes.setCreateTime(date2);
            couponDirectedReleaseRes.setAlreadyRecNum((Long) userCouponGroupMap.get("alreadyRecNum"));
            couponDirectedReleaseRes.setTotal(userCouponList.size());
            couponDirectedReleaseResList.add(couponDirectedReleaseRes);
        }
        //按创建时间和userid分组后创建时间和userid对应的map
        IdentityHashMap<Date, String> createTimeAndUserIdMap = new IdentityHashMap<>();
        for (UserCoupon userCoupon : userCoupons) {
            createTimeAndUserIdMap.put(userCoupon.getCreateTime(), userCoupon.getUserId());
        }
        IdentityHashMap<Date, String> createTimeAndPhoneMap = new IdentityHashMap<>();
        for (Map.Entry<Date, String> createTimeAndUserIdentry : createTimeAndUserIdMap.entrySet()) {
            for (Map.Entry<String, String> userInfoentry : userInfoMap.entrySet()) {
                if (createTimeAndUserIdentry.getValue().equals(userInfoentry.getKey())) {
                    createTimeAndPhoneMap.put(createTimeAndUserIdentry.getKey(), userInfoentry.getValue());
                }
            }
        }
        for (CouponDirectedReleaseRes couponDirectedReleaseRes : couponDirectedReleaseResList) {
            Set<String> phoneSet = new HashSet<>();
            Set<String> phoneFailSet = new HashSet<>();
            for (Map.Entry<Date, String> createTimeAndPhoneentry : createTimeAndPhoneMap.entrySet()) {
                if (createTimeAndPhoneentry.getKey().equals(couponDirectedReleaseRes.getCreateTime())) {
                    phoneSet.add(phoneEncoderUtil.decryptString(createTimeAndPhoneentry.getValue()));
                }
                couponDirectedReleaseRes.setPhoneSet(phoneSet);
            }
            for (Map.Entry<Date, String> failRecEntry : failRecMap.entrySet()) {
                if (failRecEntry.getKey().equals(couponDirectedReleaseRes.getCreateTime())) {
                    phoneFailSet.add(phoneEncoderUtil.decryptString(failRecEntry.getValue()));
                }
                couponDirectedReleaseRes.setPhoneFailSet(phoneFailSet);
            }

        }
        return Rs.success(couponDirectedReleaseResList);
    }


    @GetMapping("get-effective-coupons")
    @Operation(tags = "获取可用优惠券", description = "获取可用优惠券")
    public Rs<EffectiveCouponRsResponse> getEffectiveCoupons(@RequestParam Integer page, @RequestParam Integer size) {
        return Rs.success(couponRest.getEffectiveCoupons(page, size));
    }

    @GetMapping("get-normal-by-coupon-ids")
    @Operation(tags = "通过优惠券ids获取正常优惠券", description = "通过优惠券ids获取正常优惠券")
    public Rs<List<EffectiveCouponResponse>> getNormalByCouponIds(@RequestParam String couponActivityId) {
        List<EffectiveCouponResponse> effectiveCouponResponses = new ArrayList<>();
        List<CouponActivityDetail> couponActivityDetails = couponActivityDetailController.getDetailsByCouponActivityIds(Collections.singletonList(couponActivityId));
        if (!CollectionUtils.isEmpty(couponActivityDetails)) {
            List<Coupon> coupons = couponRest.getNormalByCouponIds(couponActivityDetails.stream().map(CouponActivityDetail::getCouponId).distinct().toList());
            coupons.forEach(coupon -> {
                EffectiveCouponResponse effectiveCouponResponse = BeanUtil.copyProperties(coupon, EffectiveCouponResponse.class);
                effectiveCouponResponse.setCouponTypeName(CouponTypeEnum.getDesc(coupon.getCouponType()));
                effectiveCouponResponse.setStock(coupon.getTotalQuantity() - coupon.getAlreadyRecNum());
                effectiveCouponResponse.setCouponId(coupon.getId());
                effectiveCouponResponses.add(effectiveCouponResponse);
            });
        }
        return Rs.success(effectiveCouponResponses);
    }
}
